﻿/*============================================
 * 类名 :ReplaceWork
 * 描述 :对表达式树进行节点的替换
 *   
 * 创建时间: 2010-7-24 9:57:49
 * Blog:   http://home.cnblogs.com/xiangism
 *============================================*/
using System;
using System.Collections.Generic;

using System.Text;

namespace 命题证明
{
    /// <summary>对表达式树进行节点的替换</summary>
    class ReplaceWork
    {
        public ReplaceWork( Expression e )
        {
            oldExp = e;
            NewExp = e.Clone();
            bin = new BinaryNumber( e.OperatorNodes.Count );
        }
        Expression oldExp;
        /// <summary>替换后的新表达式</summary>
        public Expression NewExp { get; set; }
        /// <summary>记录节点的替换情况，用以还原</summary>
        List<ReplaceParameter> replaces = new List<ReplaceParameter>();
        BinaryNumber bin;

        /// <summary>执行一次替换操作</summary>
        /// <param name="value">传一个整数，这个数将变成转化为二进制数，并以此为依据进行操作符节点的替换</param>
        public void Replace( int value )
        {
            bin.DecimalNumber = value;
            for ( int j = 0; j < bin.Binary.Count - 1; j++ )  //这里减了个1，不知道会不会有问题
            {
                if ( bin.Binary[j] )
                {
                    //if ( j == exp.WordNodes.Count - 1 )
                    //    continue;
                    Node oldIndex = oldExp.OperatorNodes[j];   //原来旧树上的节点
                    Node newIndex = NewExp.OperatorNodes[j];  //要作替换的新树上的节点
                    if ( CanReplace( replaces, oldIndex ) )
                    {
                        Node have = EqualReplace( oldIndex );
                        if ( have != null )
                        {
                            Replace( newIndex, have );
                            continue;
                        }

                        Node newNode = new WordNode( FindNoExist( replaces ) );
                        replaces.Add( new ReplaceParameter( newNode, oldIndex ) );
                        //现在替换节点都是在新树上进行
                        Replace( newIndex, newNode );
                        //OperatorNode op = oldIndex as OperatorNode;

                        //if ( op.Operator == Operator.Not )
                        //{
                        //    for ( int i = 0; i < oldExp.WordNodes.Count; ++i )
                        //    {
                        //        if ( oldIndex.CanOppositionReplace( oldExp.WordNodes[i] ) )
                        //        {
                        //            //OppositionReplace( NewExp.WordNodes[i] );
                        //        }
                        //    }
                        //    for ( int i = 0; i < oldExp.OperatorNodes.Count; ++i )
                        //    {
                        //        if ( oldIndex.CanOppositionReplace( oldExp.OperatorNodes[i] ) )
                        //        {
                        //            OppositionReplace( NewExp.OperatorNodes[i] );
                        //            Replace( newIndex, newNode );
                        //        }
                        //    }

                        //}

                    }

                }
            }

        }

        /// <summary>将替换后得到的结果转换回来</summary> 
        public void ReplaceBack( ref string value )
        {
            foreach ( ReplaceParameter r in replaces )
            {
                value = value.Replace(
                    ExpressionFactory.ConvertToAfter( r.NewNode ),
                    ExpressionFactory.ConvertToAfter( r.OldNode ) );
            }
        }

        /// <summary>找一个没有出现过的字母，用来替换操作符节点 </summary> 
        char FindNoExist( List<ReplaceParameter> replaces )
        {
            //for ( char c = 'a'; c <= 'z'; c++ )
            for ( char c = (char)1000; ; c++ )
            {
                if (
                    //    !exp.WordNodes.Exists( delegate( WordNode op ) {
                    //    if ( op.Word == c )
                    //        return true;
                    //    return false;
                    //} ) &&
                !replaces.Exists( delegate( ReplaceParameter r ) {
                    //if ( ( r.NewNode as WordNode ).Word == c )
                    //    return true;
                    //return false;
                    string after = ExpressionFactory.ConvertToAfter( r.NewNode );
                    foreach ( char a in after )
                    {
                        if ( a == c )
                            return true;
                    }
                    return false;
                } ) )
                {
                    return c;
                }
            }
            //throw new Exception( "超过26个字母了" );
            throw new Exception( "不可能出现的错误" );
        }

        /// <summary>如果其它节点有相等的，就直接进行替换，返回可供替代的新节点</summary> 
        Node EqualReplace( Node node )
        {
            foreach ( ReplaceParameter p in replaces )
            {
                //TODO:这里的相等也应该用后序形式完全相等来判断，这个是小问题，放在最后完成                
                if ( p.OldNode.IsEqual( node ) )
                {
                    return p.NewNode;
                }
            }
            return null;
        }

        /// <summary>这个节点是否和已经替换过的节点存在关系，如果存在就不能替换 </summary> 
        bool CanReplace( List<ReplaceParameter> replaces, Node d )
        {
            if ( replaces.Count == 0 )
                return true;
            foreach ( ReplaceParameter p in replaces )
            {
                if ( d.IsRelation( p.OldNode ) )
                    return false;
            }
            return true;
        }

        /// <summary>进行相反的替换</summary>
        void OppositionReplace( Node node )
        {
            Node add = new OperatorNode( Operator.Not );
            add.Right = node;
            add.Parent = node.Parent;
            node.Parent.Right = add;
            node.Parent = add;
        }

        void Replace( Node operatorIndex, Node newNode )
        {
            //if ( operatorIndex.Parent != null )
            //{
            if ( object.ReferenceEquals( operatorIndex.Parent.Left, operatorIndex ) )
            {
                newNode.Parent = operatorIndex.Parent;
                operatorIndex.Parent.Left = newNode;
            }
            else
            {
                newNode.Parent = operatorIndex.Parent;
                operatorIndex.Parent.Right = newNode;
            }
            //}
        }

    }
}

